package com.tencreat.service.mall.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.huifu.adapay.Adapay;
import com.huifu.adapay.model.MerConfig;
import com.huifu.adapay.model.Payment;
import com.lianlianpay.security.utils.LianLianPaySecurity;
import com.tencreat.common.config.WxPayConfiguration;
import com.tencreat.common.core.domain.entity.SysDictData;
import com.tencreat.common.core.domain.model.ReqIdParam;
import com.tencreat.common.core.domain.model.ReqStringParam;
import com.tencreat.common.enums.*;
import com.tencreat.common.enums.mall.AllEnum;
import com.tencreat.common.exception.CustomException;
import com.tencreat.common.utils.*;
import com.tencreat.common.utils.bean.*;
import com.tencreat.common.utils.http.HttpClient;
import com.tencreat.common.utils.http.HttpUtils;
import com.tencreat.common.utils.ip.IpUtils;
import com.tencreat.common.utils.pay.CertUtil;
import com.tencreat.common.utils.pay.CryptoUtil;
import com.tencreat.common.utils.pay.SDKUtil;
import com.tencreat.common.utils.uuid.SnowflakeIdWorker;
import com.tencreat.domain.account.AccountWithdrawAudit;
import com.tencreat.domain.account.AccountWithdrawInfo;
import com.tencreat.domain.account.MallUser;
import com.tencreat.domain.mall.*;
import com.tencreat.domain.mall.dto.CashIntegralPayDTO;
import com.tencreat.mapper.account.AccountWithdrawAuditMapper;
import com.tencreat.mapper.account.MallUserMapper;
import com.tencreat.mapper.mall.MallOrderMapper;
import com.tencreat.mq.BalanceChangeConsumer;
import com.tencreat.service.account.IAccountWithdrawInfoService;
import com.tencreat.service.account.IMallUserService;
import com.tencreat.service.mall.*;
import com.tencreat.service.pay.TradeService;
import com.tencreat.service.system.ISysDictDataService;
import com.upay.sdk.cashier.order.builder.ReceiptPaymentBuilder;
import com.upay.sdk.cashier.order.executer.ReceiptOrderExecuter;
import com.upay.sdk.entity.Payer;
import com.upay.sdk.entity.ProductDetail;
import com.upay.sdk.entity.TransferDomesticPayee;
import com.upay.sdk.exception.HmacVerifyException;
import com.upay.sdk.exception.RequestException;
import com.upay.sdk.exception.ResponseException;
import com.upay.sdk.exception.UnknownException;
import com.upay.sdk.executer.ResultListenerAdpater;
import com.upay.sdk.onlinepay.executer.OnlinePayOrderExecuter;
import com.upay.sdk.transferDomestic.builder.SingleOrderBuilder;
import com.upay.sdk.onlinepay.builder.OrderBuilder;
import com.upay.sdk.transferDomestic.executer.TransferDomesticSingleOrderExecuter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author huang wei
 * @version 1.0
 * @date 2021/9/2 16:27
 */
@Service
@Slf4j
public class PayServiceImpl implements IPayService {
    private final static Logger logger = LoggerFactory.getLogger("sys-pay");

    @Resource
    private IMallOrderService iMallOrderService;//订单信息

    @Autowired
    private WxPayConfiguration wxPayConfiguration;

    @Resource
    private IMallOrderGoodsService iMallOrderGoodsService;//订单商品

    @Resource
    private IMallGoodsService iMallGoodsService;//商品信息

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Resource
    private WxPayService wxService;


    @Resource
    private IMallUserService mallUserService;//用户

    @Autowired
    private TradeService tradeService;

    @Autowired
    private IRechargeOrderService rechargeOrderService;//充值提现

    @Autowired
    private IBalanceChangeService balanceChangeService;//余额变动

    @Autowired
    private MallUserMapper mallUserMapper;

    @Autowired
    private MallOrderMapper mallOrderMapper;

    @Autowired
    private MallMultipleOrderServiceImpl mallMultipleOrderService;//订单关联
    @Resource
    private RabbitSendUtils rabbitUtils;
    @Autowired
    private IAccountWithdrawInfoService accountWithdrawInfoService;//提现接口
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private AccountWithdrawAuditMapper accountWithdrawAuditMapper;
    @Autowired
    private BalanceChangeConsumer balanceChangeConsumer;
    @Autowired
    private ISysDictDataService sysDictDataService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    private final static Integer[] times = {5, 10, 30, 60, 120, 600, 3600};


    @Override
    public <T> T createWxOrder(ReqStringParam param) throws WxPayException {
        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();
        WxPayService wxPayService = null;
//        WxPayService wxPayService = wxPayConfiguration.wxService();
        if ("MWEB".equals(param.getTradeType()) && StringUtils.isNotEmpty(param.getTradeType())) {
            wxPayService = wxPayConfiguration.wxServiceH5();
        }
        if ("APP".equals(param.getTradeType()) && StringUtils.isNotEmpty(param.getTradeType())) {
            wxPayService = wxPayConfiguration.wxService();
        }
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setAppid(wxPayService.getConfig().getAppId());
        request.setMchId(wxPayService.getConfig().getMchId());
        if (order.getOrderType() == OrderType.RECHARGE) {
            request.setDetail(OrderType.RECHARGE.getDesc());
        } else {
            MallOrderGoods mallOrderGood = iMallOrderGoodsService.lambdaQuery().eq(MallOrderGoods::getOrderSn, order.getOrderSn()).list().get(0);
            request.setDetail(mallOrderGood.getGoodsName());
        }
        log.info("私钥"+wxPayService.getConfig().getMchKey());
        request.setOutTradeNo(order.getOrderSn());
        //支付回调地址
        request.setNotifyUrl(wxPayService.getConfig().getNotifyUrl());
        request.setFeeType("CNY");
        BigDecimal actualPrice = order.getActualPrice();

        request.setTotalFee(actualPrice.multiply(BigDecimal.valueOf(100L)).intValue());
        request.setSpbillCreateIp(IpUtils.getIpAddr(httpServletRequest));
//        request.setTradeType("APP");
//        request.setTradeType("MWEB");
        request.setTradeType(param.getTradeType());
        request.setBody("支付");

//        order.setPayType(PayType.WX_PAY);
//        order.setPayType(PayType.WX_PAY_H5);
        order.setPayType(param.getTradeType().equals("APP")?PayType.WX_PAY:PayType.WX_PAY_H5);
        order.setPayTime(new Date());
        order.setUpdateTime(LocalDateTime.now());
        iMallOrderService.updateById(order);

        if(order.getOrderType().compareTo(OrderType.RECHARGE)==0){
            RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
            rechargeOrder.setPayTime(LocalDateTime.now());
//            rechargeOrder.setPayType(PayType.WX_PAY);
//            rechargeOrder.setPayType(PayType.WX_PAY_H5);
            rechargeOrder.setPayType(param.getTradeType().equals("APP")?PayType.WX_PAY:PayType.WX_PAY_H5);
            rechargeOrderService.updateById(rechargeOrder);
        }


        //设置支付方式
        return wxService.createOrder(request);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public <T> T createWxOrders(List<String> commons,String tradeType) throws WxPayException {
//        WxPayService wxPayService = wxPayConfiguration.wxService();
        WxPayService wxPayService = null;
//        WxPayService wxPayService = wxPayConfiguration.wxService();
        if ("MWEB".equals(tradeType) && StringUtils.isNotEmpty(tradeType)) {
            wxPayService = wxPayConfiguration.wxServiceH5();
        }
        if ("APP".equals(tradeType) && StringUtils.isNotEmpty(tradeType)) {
            wxPayService = wxPayConfiguration.wxService();
        }

        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setAppid(wxPayService.getConfig().getAppId());
        request.setMchId(wxPayService.getConfig().getMchId());
        String outTradeNo = "multiple_"+ TenCreatUtil.getOrderNo();
        // 多个订单号组合支付，总金额
        BigDecimal money = new BigDecimal("0.00");
        for (int i = 0; i < commons.size(); i++) {
            MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, commons.get(i)).one();
            money = money.add(order.getActualPrice());
//            order.setPayType(PayType.WX_PAY);
            order.setPayType(tradeType.equals("APP")?PayType.WX_PAY:PayType.WX_PAY_H5);
            order.setPayTime(new Date());
            order.setUpdateTime(LocalDateTime.now());
            iMallOrderService.updateById(order);
            MallMultipleOrder mallMultipleOrder = new MallMultipleOrder();
            mallMultipleOrder.setOrderId(commons.get(i));
            mallMultipleOrder.setMuOrderId(outTradeNo);
            mallMultipleOrderService.insertMallMultipleOrder(mallMultipleOrder);
        }
        request.setOutTradeNo(outTradeNo);
        //支付回调地址
        request.setNotifyUrl(wxPayService.getConfig().getNotifyUrl());
        request.setFeeType("CNY");
        request.setTotalFee(money.multiply(BigDecimal.valueOf(100L)).intValue());
        request.setSpbillCreateIp(IpUtils.getIpAddr(httpServletRequest));
//        request.setTradeType("APP");
        request.setTradeType(tradeType);
        request.setBody("支付");
//        request.

        //设置支付方式
        return wxService.createOrder(request);
    }

    /**
     * 进行微信提现操作 （企业付款至用户零钱）
     *
     * @param openId
     * @param amount         提现金额
     * @param partnerTradeNo 单号
     * @param desc           备注
     */
    private EntPayResult getWithdrawal(String openId, BigDecimal amount, String partnerTradeNo, String desc, HttpServletRequest request) {
        WxPayService wxPayService = wxPayConfiguration.wxService();
        EntPayRequest entPayRequest = new EntPayRequest();
        entPayRequest.setAppid(wxPayService.getConfig().getAppId());
        entPayRequest.setMchId(wxPayService.getConfig().getMchId());
        entPayRequest.setPartnerTradeNo(partnerTradeNo);
        entPayRequest.setOpenid(openId);
        entPayRequest.setCheckName("NO_CHECK");
        entPayRequest.setAmount(Integer.valueOf(amount.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString()));
        entPayRequest.setDescription(desc);
        entPayRequest.setSpbillCreateIp(IpUtils.getIpAddr(request));
        EntPayResult entPayResult = null;
        try {
            //此处调用=============================================================
            entPayResult = wxPayService.getEntPayService().entPay(entPayRequest);
            logger.info("entPayResult : " + entPayResult);
            System.out.println(entPayResult);
        } catch (WxPayException e) {
            logger.error("付款失败，返回报文" + e);
            throw new ApiException(e.getCustomErrorMsg());
        }
        return entPayResult;
    }


    /**
     * 描述信息 有买有卖消费券支付
     *
     * @Author yaoruiqi
     * @Date: 2023/10/08 05:58
     */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    @Override
    public ConcurrentHashMap<String, Object> consumerRollPay(ReqStringParam param) {
        ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
        logger.info(String.format("订单消费券支付,订单id：%s", param));
//        String lockKey = "consumerRoll_pay" + param.getUuid();
//        RLock lock = redissonClient.getLock(lockKey);
//        lock.lock(10, TimeUnit.SECONDS);
        // 先锁再开启事务
//        TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
        try {
            //order info 订单信息
            MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();

            //user info 用户uuid
            MallUser user = mallUserService.lambdaQuery().eq(MallUser::getUuid, order.getUuid()).one();

            // 校验用户支付密码
            if (user.getPayPassword() == null || !user.getPayPassword().equals(param.getPayPassword())) {
                throw new CustomException("支付密码错误！");
            }
            //消费券支付校验
            BigDecimal userConsumerRoll = user.getConsumerRoll();

            if (userConsumerRoll == null) {
                map.put("info", "消费券不足,请充值");
                throw new CustomException("消费券不足,请充值");
            }

            BigDecimal actualPrice = order.getActualPrice();

            if (userConsumerRoll.compareTo(actualPrice) < 0) {
                map.put("info", "消费券不足,请充值");
                throw new CustomException("消费券不足,请充值");
            }

            //更新订单信息
            order.setPayType(PayType.CR_PAY);
            order.setPayTime(new Date());
            order.setUpdateTime(LocalDateTime.now());
            if (OrderType.SHOP.equals(order.getOrderType())){
                order.setOrderStatus(OrderStatus.WAIT_DELIVER);
            }
            if (OrderType.STORE.equals(order.getOrderType())){
                order.setOrderStatus(OrderStatus.WAIT_USE);
            }
            if (OrderType.QR_CODE_ORDER.equals(order.getOrderType())){
                order.setOrderStatus(OrderStatus.PAID);
            }

            // 消费券变动队列
            sendBalanceMessageAsync(order.getUuid(),order.getActualPrice().negate(),"2",BalanceBusinessType.USE,"消费券支付",order.getOrderSn(),BalanceTypeEnum.CONSUMER_ROLL);
            //提货单变动队列
            //sendBalanceMessageAsync(order.getUuid(),order.getActualPrice().negate(),"2",BalanceBusinessType.USE,"提货单变化",order.getOrderSn(),BalanceTypeEnum.CONSUMER_ROLL);

            //消费券支付回调
            tradeService.afterPaySuccess(null, order);

//            platformTransactionManager.commit(transaction);
            return null;
        } catch (Exception e) {
            map.put("info", e.getMessage());
//            iMallOrderService.deleteMallOrderById(new ReqIdParam(iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one().getId()));
//            platformTransactionManager.rollback(transaction);

            throw new CustomException(e.getMessage());
        } finally {
//            if (lock.isHeldByCurrentThread()) { // 是当前执行线程的锁
//                log.info("消费券支付释放锁--------------------" + lockKey);
//                lock.unlock(); // 释放锁
//            }
        }
    }


    public void sendBalanceMessageAsync(Long uuid, BigDecimal amount, String type, BalanceBusinessType use,  String remark,String source,BalanceTypeEnum balanceType) throws Exception{
        log.info("同步变动余额----------UUID：{},type:{},amount:{},use:{}，auctionPay：{}，remark：{}-------",uuid,type,amount,use.getDesc(),remark);
        if(amount.compareTo(BigDecimal.ZERO) == 0){
            return;
        }
        //修改用户余额
        UserBalanceChange message = new UserBalanceChange();
        message.setUuid(uuid);
        message.setChangAmount(amount);
        message.setType(type);
        message.setBusinessType(use);
        message.setRemark(remark);
        message.setSource(source);
        message.setBalanceType(balanceType);
        // 发送余额变动消息
        balanceChangeConsumer.doJobAsync(message);
    }

/*    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cashIntegralPay(CashIntegralPayDTO dto) {
        Long uuid = SecurityUtils.getLoginUser().getAccountLogin().getUuid();
        // 锁订单
        MallOrder mallOrder = mallOrderMapper.selectForUpdate(dto.getOrderSn());
        if (mallOrder.getOrderStatus() != OrderStatus.PAY){
            throw new CustomException("支付失败，该订单不是待支付");
        }
        // 锁用户
        MallUser mallUser = mallUserMapper.selectForUpdate(uuid);
        // 校验用户支付密码
        if (mallUser.getPayPassword() == null || !mallUser.getPayPassword().equals(dto.getPayPassword())) {
            throw new CustomException("支付密码错误！");
        }
        // 校验订单
        verifyPayOrder(mallOrder);
        // 校验用户余额够不够
        if (mallOrder.getOrderPrice().compareTo(mallUser.getConsumerRoll())>0) {
            throw new CustomException("消费券不足");
        }
        try {
            // 设置订单
            mallOrder.setPayType(PayType.CR_PAY);
            mallOrder.setOrderStatus(OrderStatus.WAIT_SHIP);
            mallOrder.setStatusUser(UserOrderStatus.OK);
            mallOrder.setStatusShop(ShopOrderStatus.WAIT_SHIP);
            mallOrder.setActualPrice(mallOrder.getOrderPrice());
            mallOrder.setPayTime(new Date());

            iMallOrderService.updateById(mallOrder);
            iMallOrderGoodsService.lambdaUpdate().eq(MallOrderGoods::getOrderSn,mallOrder.getOrderSn())
                    .set(MallOrderGoods::getOrderStatus,mallOrder.getOrderStatus())
                    .update();
            // 设置流水及更改用户余额
            sendBalanceMessageAsync(uuid,mallOrder.getOrderPrice().negate(),AllEnum.BalanceChangeTypeEnums.EXPENDITURE.getType(), BalanceBusinessType.USE,"积分支付",mallOrder.getOrderSn(),BalanceTypeEnum.CASH_INTEGRAL);
        } catch (Exception e) {
            logger.error("info{}",e.getMessage());
            throw new CustomException("支付失败");
        }

    }*/

/*    @Transactional(rollbackFor = Exception.class)
    @Override
    public void shopIntegralPay(CashIntegralPayDTO dto) {
        Long uuid = SecurityUtils.getLoginUser().getAccountLogin().getUuid();
        // 锁订单
        MallOrder mallOrder = mallOrderMapper.selectForUpdate(dto.getOrderSn());
        // 锁用户
        MallUser mallUser = mallUserMapper.selectForUpdate(uuid);
        // 校验用户支付密码
        if (mallUser.getPayPassword() == null || !mallUser.getPayPassword().equals(dto.getPayPassword())) {
            throw new CustomException("支付密码错误！");
        }
        // 校验订单
        verifyPayOrder(mallOrder);
//        Long orderPrice = Long.parseLong(mallOrder.getOrderPrice().setScale(0).toString());
        // 校验用户余额够不够
        if (mallOrder.getOrderPrice().compareTo(mallUser.getBuyIntegral())>0) {
            throw new CustomException("购物积分不足");
        }
        // 设置订单
        try {
            mallOrder.setPayType(PayType.CASH_POINTS);
            mallOrder.setOrderStatus(OrderStatus.WAIT_SHIP);
            mallOrder.setStatusUser(UserOrderStatus.OK);
            mallOrder.setStatusShop(ShopOrderStatus.WAIT_SHIP);
            mallOrder.setActualPrice(mallOrder.getOrderPrice());
            mallOrder.setPayTime(new Date());

            iMallOrderService.updateById(mallOrder);
            iMallOrderGoodsService.lambdaUpdate().eq(MallOrderGoods::getOrderSn,mallOrder.getOrderSn())
                    .set(MallOrderGoods::getOrderStatus,mallOrder.getOrderStatus())
                    .update();
            // 设置流水及更改用户余额
            sendBalanceMessageAsync(uuid,mallOrder.getOrderPrice().negate(),AllEnum.BalanceChangeTypeEnums.EXPENDITURE.getType(), BalanceBusinessType.USE,"积分支付",mallOrder.getOrderSn(),BalanceTypeEnum.BUY_INTEGRAL);
        } catch (Exception e) {
            logger.error("info{}",e.getMessage());
            throw new CustomException("支付错误！");
        }
    }*/

    /**
     * 校验待支付的订单
     */
    void verifyPayOrder(MallOrder order) {
        if (OrderStatus.PAY != order.getOrderStatus()) {
            throw new CustomException("订单已支付或已取消");
        }
    }

    @Override
    @Transactional
    public String parseWxOrderNotifyResult(String xmlData) throws WxPayException {
        WxPayOrderNotifyResult wxPayOrderNotifyResult = wxService.parseOrderNotifyResult(xmlData);
        String outtradeNo = wxPayOrderNotifyResult.getOutTradeNo();
        // 多订单组合支付处理
        if (outtradeNo.indexOf("multiple_") > -1) {

            if ("SUCCESS".equals(wxPayOrderNotifyResult.getResultCode())) {
                List<MallMultipleOrder> mallMultipleOrders = mallMultipleOrderService.selectByMuOrderId(new ReqStringParam().setCommon(outtradeNo));

                for (MallMultipleOrder mallMultipleOrder : mallMultipleOrders) {
                    MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, mallMultipleOrder.getOrderId()).one();
                    tradeService.afterPaySuccess(wxPayOrderNotifyResult.getTransactionId(), order);
                }
            }

            return "<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> </xml>";
        } else {
            MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, wxPayOrderNotifyResult.getOutTradeNo()).one();

            if ("SUCCESS".equals(wxPayOrderNotifyResult.getResultCode())) {
                tradeService.afterPaySuccess(wxPayOrderNotifyResult.getTransactionId(), order);
            } else {
                iMallOrderService.deleteMallOrderById(new ReqIdParam(order.getId()));
            }

            return "<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> </xml>";
        }
    }


    @Override
    @Transactional
    public void parseAliPayOrderNotifyResult(Map<String, String> map, Boolean flag) {
        // 多订单组合支付处理
        if (map.get("out_trade_no").indexOf("multiple_") > -1) {
            List<MallMultipleOrder> mallMultipleOrders = mallMultipleOrderService.selectByMuOrderId(new ReqStringParam().setCommon(map.get("out_trade_no")));
            if (flag) {
                for (MallMultipleOrder mallMultipleOrder : mallMultipleOrders) {
                    MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, mallMultipleOrder.getOrderId()).one();
                    if (order == null) {
                        logger.error(new cn.hutool.json.JSONObject(map).toString());
                    }
                    tradeService.afterPaySuccess(map.get("trade_no"), order);
                }
            }
        } else {
            MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, map.get("out_trade_no")).one();
            if (order == null) {
                logger.error(new cn.hutool.json.JSONObject(map).toString());
            }
            if (flag) {
                //设置支付方式
                tradeService.afterPaySuccess(map.get("trade_no"), order);
            } else {
                iMallOrderService.deleteMallOrderById(new ReqIdParam(order.getId()));
            }
        }
    }

    @Override
    public void createAliPayCertificateOrder(ReqStringParam param) throws AlipayApiException {
        Map<String, String> map = aliPayConfig();
        //构造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        //设置网关地址
        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
        //设置应用Id
        certAlipayRequest.setAppId(map.get("app_id"));
        //设置应用私钥
        certAlipayRequest.setPrivateKey(map.get("privateKey"));
        //设置请求格式，固定值json
        certAlipayRequest.setFormat("json");
        //设置字符集
        certAlipayRequest.setCharset("utf-8");
        //设置签名类型
        certAlipayRequest.setSignType("RSA2");
        //设置应用公钥证书路径
        certAlipayRequest.setCertPath(map.get("app_cert_path"));
        //设置支付宝公钥证书路径
        certAlipayRequest.setAlipayPublicCertPath(map.get("alipay_cert_path"));
        //设置支付宝根证书路径
        certAlipayRequest.setRootCertPath(map.get("alipay_root_cert_path"));
        //构造client
        AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();

        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();
        MallOrderGoods mallOrderGood = iMallOrderGoodsService.lambdaQuery().eq(MallOrderGoods::getOrderSn, order.getId()).one();
        MallGoods goods = iMallGoodsService.getById(mallOrderGood.getGoodsId());
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(goods.getBrief());
        model.setSubject(goods.getName());
        model.setOutTradeNo(param.getCommon());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(order.getActualPrice().toString());
        /*
        产品码。
        商家和支付宝签约的产品码。 枚举值（点击查看签约情况）：
        QUICK_MSECURITY_PAY：无线快捷支付产品；
        CYCLE_PAY_AUTH：周期扣款产品。
        默认值为QUICK_MSECURITY_PAY。
        */
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(map.get("notifyUrlCertificate"));
        //这里和普通的接口调用不同，使用的是sdkExecute
        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
        //就是orderString 可以直接给客户端请求，无需再做处理。
        System.out.println(response.getBody());

        //设置支付方式
        order.setPayType(PayType.ALI_PAY);
        order.setPayTime(new Date());
        order.setPayId(response.getTradeNo());
        order.setUpdateTime(LocalDateTime.now());
        iMallOrderService.updateById(order);
    }

    @Override
    public void createAliPayCertificateOrders(List<String> commons) throws AlipayApiException {
        Map<String, String> map = aliPayConfig();
        //构造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        //设置网关地址
        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
        //设置应用Id
        certAlipayRequest.setAppId(map.get("app_id"));
        //设置应用私钥
        certAlipayRequest.setPrivateKey(map.get("privateKey"));
        //设置请求格式，固定值json
        certAlipayRequest.setFormat("json");
        //设置字符集
        certAlipayRequest.setCharset("utf-8");
        //设置签名类型
        certAlipayRequest.setSignType("RSA2");
        //设置应用公钥证书路径
        certAlipayRequest.setCertPath(map.get("app_cert_path"));
        //设置支付宝公钥证书路径
        certAlipayRequest.setAlipayPublicCertPath(map.get("alipay_cert_path"));
        //设置支付宝根证书路径
        certAlipayRequest.setRootCertPath(map.get("alipay_root_cert_path"));
        //构造client
        AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        StringBuilder outTradeNo = new StringBuilder();
        BigDecimal money = new BigDecimal("0.00");
        for (int i = 0; i < commons.size(); i++) {
            MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, commons.get(i)).one();
            outTradeNo.append(commons.get(i));
            money.add(order.getActualPrice());
            //设置支付方式
            order.setPayType(PayType.ALI_PAY);
            order.setPayTime(new Date());
//            order.setPayId(response.getTradeNo());
            order.setUpdateTime(LocalDateTime.now());
            iMallOrderService.updateById(order);
            if (i != commons.size() - 1) {
                outTradeNo.append(",");
            }
        }
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setOutTradeNo(outTradeNo.toString());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(money.toString());
        /*
        产品码。
        商家和支付宝签约的产品码。 枚举值（点击查看签约情况）：
        QUICK_MSECURITY_PAY：无线快捷支付产品；
        CYCLE_PAY_AUTH：周期扣款产品。
        默认值为QUICK_MSECURITY_PAY。
        */
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(map.get("notifyUrlCertificate"));
        //这里和普通的接口调用不同，使用的是sdkExecute
        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
        //就是orderString 可以直接给客户端请求，无需再做处理。
        System.out.println(response.getBody());
    }


    @Override
    public String createAliPayOrder(ReqStringParam param) throws AlipayApiException {

        Map<String, String> map = aliPayConfig();
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(
                "https://openapi.alipay.com/gateway.do"
                , map.get("app_id")
                , map.get("privateKey")
                , "json"
                , "utf-8"
                , map.get("ALIPAY_PUBLIC_KEY")
                , "RSA2");
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();

        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();


        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
//        model.setBody(goods.getBrief());
        if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
            model.setSubject("账户充值");
        } else {
            List<MallOrderGoods> mallOrderGoods = iMallOrderGoodsService.lambdaQuery().eq(MallOrderGoods::getOrderSn, order.getOrderSn()).list();
            StringBuilder stringBuilder = new StringBuilder();
            for (MallOrderGoods mallOrderGood : mallOrderGoods) {
                MallGoods goods = iMallGoodsService.getById(mallOrderGood.getGoodsId());
                stringBuilder.append(goods.getName());
            }
            model.setSubject(stringBuilder.toString());
        }
        model.setOutTradeNo(param.getCommon());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(order.getActualPrice().toString());
//        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(map.get("notifyUrl"));
        String ailipay = "";
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            //就是orderString 可以直接给客户端请求，无需再做处理。
            ailipay = response.getBody();

            //设置支付方式
            order.setPayType(PayType.ALI_PAY);
            order.setPayTime(new Date());
            order.setPayId(response.getTradeNo());
            order.setUpdateTime(LocalDateTime.now());
            iMallOrderService.updateById(order);

            if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
                RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
                rechargeOrder.setPayId(response.getTradeNo());
                rechargeOrder.setPayTime(LocalDateTime.now());
                rechargeOrder.setPayType(PayType.ALI_PAY);
                rechargeOrderService.updateById(rechargeOrder);
            }

        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return ailipay;
    }


    /**
     * 描述信息  支付宝h5支付
     *
     * @Author yaoruiqi
     * @Date: 2023/11/13 04:33
     */

    @Override
    public String createAliPayH5Order(ReqStringParam param) {
        Map<String, String> map = aliPayConfig2();
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(
                "https://openapi.alipay.com/gateway.do"
                , map.get("app_id")
                , map.get("privateKey")
                , "json"
                , "utf-8"
                , map.get("ALIPAY_PUBLIC_KEY")
                , "RSA2");
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();

        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();


        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
            model.setSubject("账户充值");
        } else {
            MallGoods goods = iMallGoodsService.getById(order.getGoodsId());
            model.setSubject(goods.getName());
        }
        model.setOutTradeNo(param.getCommon());
        model.setTimeExpire(LocalDateTimeUtil.format(order.getEndTime(), "yyyy-MM-dd HH:mm:ss"));
        model.setTotalAmount(order.getActualPrice().toString());
        String returnUrl = StrUtil.format(map.get("return_url"), order.getOrderSn());
        request.setReturnUrl(map.get("return_url"));
        String quitUrl = StrUtil.format(map.get("quit_url"), order.getGoodsId(), order.getOrderSn());
        model.setQuitUrl(quitUrl);
        request.setBizModel(model);
        request.setNotifyUrl(map.get("notifyUrl"));
        String ailipay = "";
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
            //就是orderString 可以直接给客户端请求，无需再做处理。
            ailipay = response.getBody();

            //设置支付方式
            order.setPayType(PayType.ALI_PAY_H5);
            order.setPayTime(new Date());
            order.setPayId(response.getTradeNo());
            order.setUpdateTime(LocalDateTime.now());
            iMallOrderService.updateById(order);

            if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
                RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
                rechargeOrder.setPayId(response.getTradeNo());
                rechargeOrder.setPayTime(LocalDateTime.now());
                rechargeOrder.setPayType(PayType.ALI_PAY);
                rechargeOrderService.updateById(rechargeOrder);
            }

        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return ailipay;
    }

    @Override
    public String createAliPayOrders(List<String> commons) throws AlipayApiException {
        Map<String, String> map = aliPayConfig();
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(
                "https://openapi.alipay.com/gateway.do"
                , map.get("app_id")
                , map.get("privateKey")
                , "json"
                , "utf-8"
                , map.get("ALIPAY_PUBLIC_KEY")
                , "RSA2");
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        String outTradeNo = "multiple_" + TenCreatUtil.getOrderNo();
        BigDecimal money = new BigDecimal("0.00");
        for (int i = 0; i < commons.size(); i++) {
            MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, commons.get(i)).one();
            money = money.add(order.getActualPrice());
            order.setPayType(PayType.ALI_PAY);
            order.setPayTime(new Date());
            order.setUpdateTime(LocalDateTime.now());
            iMallOrderService.updateById(order);
            MallMultipleOrder mallMultipleOrder = new MallMultipleOrder();
            mallMultipleOrder.setOrderId(commons.get(i));
            mallMultipleOrder.setMuOrderId(outTradeNo);
            mallMultipleOrderService.insertMallMultipleOrder(mallMultipleOrder);
        }
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setOutTradeNo(outTradeNo);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(money.toString());
        model.setSubject(String.join(",", commons));
        request.setBizModel(model);
        request.setNotifyUrl(map.get("notifyUrl"));

        String ailipay = "";
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            //就是orderString 可以直接给客户端请求，无需再做处理。
            ailipay = response.getBody();

        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return ailipay;
    }

    @Override
    public JSONObject alipayTradeRefund(ReqStringParam param) throws AlipayApiException {

        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param).one();

        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", "app_id", "your private_key", "json", "GBK", "alipay_public_key", "RSA2");
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("trade_no", order.getPayId());
        bizContent.put("refund_amount", order.getActualPrice());
        bizContent.put("out_request_no", SnowflakeIdWorker.generateId());
        bizContent.put("out_trade_no", param.getCommon());


        request.setBizContent(bizContent.toString());
        AlipayTradeRefundResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }
        return JSONObject.parseObject(response.toString());
    }

    @Override
    public WxPayRefundResult refundWx(ReqStringParam param) throws WxPayException {
        WxPayRefundRequest request = new WxPayRefundRequest();
        request.setOutTradeNo(param.getCommon());
        //商家退款订单号
        request.setOutRefundNo("");

        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param).one();
        //退款回调地址
        request.setNotifyUrl("");
        request.setRefundFee(order.getActualPrice().intValue() * 100);
        request.setTotalFee(order.getActualPrice().intValue() * 100);
        return wxService.refund(request);
    }

    // 获取支付宝配置
    public static Map<String, String> aliPayConfig() {
        List<SysDictData> wxPayConfig = DictUtils.getDictCache("alipay_config");
        Map<String, String> map = new HashMap<>(6);
        assert wxPayConfig != null;
        wxPayConfig.forEach(i -> {
            if ("app_id".equals(i.getDictLabel())) {
                map.put("app_id", i.getDictValue());
            }
            if ("notifyUrl".equals(i.getDictLabel())) {
                map.put("notifyUrl", i.getDictValue());
            }
            if ("notifyUrlCertificate".equals(i.getDictLabel())) {
                map.put("notifyUrlCertificate", i.getDictValue());
            }
            if ("privateKey".equals(i.getDictLabel())) {
                map.put("privateKey", i.getDictValue());
            }
            if ("ALIPAY_PUBLIC_KEY".equals(i.getDictLabel())) {
                map.put("ALIPAY_PUBLIC_KEY", i.getDictValue());
            }
            if ("app_cert_path".equals(i.getDictLabel())) {
                map.put("app_cert_path", i.getDictValue());
            }
            if ("alipay_cert_path".equals(i.getDictLabel())) {
                map.put("alipay_cert_path", i.getDictValue());
            }
            if ("alipay_root_cert_path".equals(i.getDictLabel())) {
                map.put("alipay_root_cert_path", i.getDictValue());
            }
        });
        return map;
    }

    // 获取首信易配置
    public static Map<String, String> sxyPayConfig() {
        List<SysDictData> wxPayConfig = DictUtils.getDictCache("sxy_pay");
        Map<String, String> map = new HashMap<>();
        assert wxPayConfig != null;
        wxPayConfig.forEach(i -> {
            // 商户ID
            if ("merchant_id".equals(i.getDictLabel())) {
                map.put("merchant_id", i.getDictValue());
            }
            // 回调地址
            if ("notify_url".equals(i.getDictLabel())) {
                map.put("notify_url", i.getDictValue());
            }
            // 跳转地址
            if ("callback_url".equals(i.getDictLabel())) {
                map.put("callback_url", i.getDictValue());
            }
            // 银行卡绑定回调地址
            if ("bank_botify_url".equals(i.getDictLabel())) {
                map.put("bank_botify_url", i.getDictValue());
            }
            // 代付回调地址
            if ("behalf_notify_url".equals(i.getDictLabel())) {
                map.put("behalf_notify_url", i.getDictValue());
            }
        });
        return map;
    }

    // 连连支付配置
    public static Map<String, String> lianlianPayConfig() {
        List<SysDictData> wxPayConfig = DictUtils.getDictCache("lianlian_pay");
        Map<String, String> map = new HashMap<>();
        assert wxPayConfig != null;
        wxPayConfig.forEach(i -> {
            // 商户号
            if ("oid_partner".equals(i.getDictLabel())) {
                map.put("oid_partner", i.getDictValue());
            }
            // 回调地址
            if ("notify_url".equals(i.getDictLabel())) {
                map.put("notify_url", i.getDictValue());
            }
            // 私钥
            if ("private_key".equals(i.getDictLabel())) {
                map.put("private_key", i.getDictValue());
            }
            // 平台公钥
            if ("publick_key".equals(i.getDictLabel())) {
                map.put("publick_key", i.getDictValue());
            }
            // 代付回调地址
            if ("behalf_notify_url".equals(i.getDictLabel())) {
                map.put("behalf_notify_url", i.getDictValue());
            }
        });
        return map;
    }

    // 汇付支付配置
    public static Map<String, String> adapayPayConfig() {
        List<SysDictData> wxPayConfig = DictUtils.getDictCache("adapay_pay");
        Map<String, String> map = new HashMap<>();
        assert wxPayConfig != null;
        wxPayConfig.forEach(i -> {
            // apiKey
            if ("api_key".equals(i.getDictLabel())) {
                map.put("api_key", i.getDictValue());
            }
            // mockApiKey
            if ("mock_api_key".equals(i.getDictLabel())) {
                map.put("mock_api_key", i.getDictValue());
            }
            // 私钥
            if ("rsa_private_key".equals(i.getDictLabel())) {
                map.put("rsa_private_key", i.getDictValue());
            }
            // appID
            if ("app_id".equals(i.getDictLabel())) {
                map.put("app_id", i.getDictValue());
            }
            // 回调地址
            if ("notify_url".equals(i.getDictLabel())) {
                map.put("notify_url", i.getDictValue());
            }
        });
        return map;
    }

    /**
     * 首信易 快捷支付
     *
     * @param param
     * @return Object
     * @Author lx
     * @Date: 2022/06/16 05:57
     */
    @Override
    @Transactional
    public Object sxyBankPay(ReqStringParam param) {
        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();
        if (order.getEndTime() != null && order.getEndTime().isBefore(LocalDateTime.now())) {
            throw new CustomException("订单已过期,请返回重新下单");
        }
        long minutes = 5;
        if (order.getOrderType().getValue() == OrderType.SHOP.getValue()) {
            minutes = ChronoUnit.MINUTES.between(LocalDateTime.now(), order.getEndTime());
        }
        Map<String, String> sxyPayConfig = sxyPayConfig();
        if (sxyPayConfig == null || sxyPayConfig.size() <= 0) {
            throw new CustomException("支付配置有误");
        }
        log.info("过期时间------" + minutes);
        OrderBuilder builder = new OrderBuilder(sxyPayConfig.get("merchant_id"));
        builder.setRequestId(order.getOrderSn()).setOrderAmount(order.getActualPrice().multiply(BigDecimal.valueOf(100L)).intValue() + "").setOrderCurrency("CNY")
                .setNotifyUrl(sxyPayConfig.get("notify_url")).setCallbackUrl(sxyPayConfig.get("callback_url")).setRemark(order.getRemark())
                .setPaymentModeCode("").setMerchantUserId(order.getUuid() + "").setClientIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        builder.setTimeout(minutes + "");
        if (param.getBandCartId() != null) {
            builder.setBindCardId(param.getBandCartId());
            builder.setPaymentModeCode("BANK_CARD-AGREEMENT-P2P");
        }
        ProductDetail productDetail = new ProductDetail();
        productDetail.setName("充值");
        productDetail.setQuantity(1L);
        productDetail.setAmount(order.getActualPrice().multiply(BigDecimal.valueOf(100L)).longValue());
        builder.addProductDetail(productDetail);
        // 银行卡信息
        Payer payer = new Payer();

        builder.setPayer(payer);
        final JSONObject data = new JSONObject();
        try {
            OnlinePayOrderExecuter executer = new OnlinePayOrderExecuter();
            System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");
            executer.bothOrder(builder, new ResultListenerAdpater() {
                /**
                 * 提交成功，不代表支付成功
                 */
                @Override
                public void success(com.alibaba.fastjson15.JSONObject jsonObject) {
                    log.info("success jsonObject:[" + jsonObject + "]");
                    if (jsonObject.get("scanCode") != null || param.getBandCartId() != null) {
                        try {
                            data.put("status", jsonObject.getString("status"));
                            data.put("redirectUrl", jsonObject.getString("redirectUrl"));
                            data.put("outTradeNo", jsonObject.getString("requestId"));
                            // order.setPayType(PayType.FAST_PAYMENT);
                            order.setPayTime(new Date());
                            order.setUpdateTime(LocalDateTime.now());
                            order.setPayId(jsonObject.getString("paymentOrderId"));
                            // order.setOrderStatus(OrderStatus.WAIT_SHIP);
                            iMallOrderService.updateById(order);
                            if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
                                RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
                                rechargeOrder.setPayTime(LocalDateTime.now());
                                rechargeOrderService.updateById(rechargeOrder);
                            }
                        } catch (Exception e) {
                            log.info("响应异常</br>" + e.toString());
                            throw new CustomException("响应异常");
                        }
                    }
                    log.info("提交成功</br>");
                    log.info(jsonObject + "");
                }

                @Override
                public void redirect(com.alibaba.fastjson15.JSONObject jsonObject, String redirectUrl) throws IOException {
                    log.debug("redirectUrl:[" + redirectUrl + "]");
                    // HttpSession session = req.getSession();
                    try {
                        data.put("status", jsonObject.getString("status"));
                        data.put("redirectUrl", jsonObject.getString("redirectUrl"));
                        data.put("outTradeNo", jsonObject.getString("requestId"));
                        order.setPayType(PayType.BANKCARD);
                        order.setPayTime(new Date());
                        order.setUpdateTime(LocalDateTime.now());
                        order.setPayId(jsonObject.getString("paymentOrderId"));
                        // order.setOrderStatus(OrderStatus.WAIT_SHIP);
                        iMallOrderService.updateById(order);
                        if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
                            RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
                            rechargeOrder.setPayTime(LocalDateTime.now());
                            rechargeOrder.setPayType(PayType.BANKCARD);
                            rechargeOrderService.updateById(rechargeOrder);
                        }
                    } catch (Exception e) {
                        log.info("响应异常</br>" + e.toString());
                        throw new CustomException("响应异常");
                    }
                }
            });
        } catch (ResponseException e) {
            log.error("响应异常</br>" + e.toString());
            throw new CustomException("响应异常");
        } catch (HmacVerifyException e) {
            log.error("签名验证异常</br>" + e.toString());
            throw new CustomException("签名验证异常");
        } catch (RequestException e) {
            log.error("请求异常</br>" + e.toString());
            throw new CustomException("请求异常</br>");
        } catch (UnknownException e) {
            log.error("未知异常</br>" + e.toString());
            throw new CustomException("未知异常");
        }

        return data;
    }

    /**
     * 下单确认
     *
     * @return 结果
     * @Author lx
     * @Date: 2022/07/01 07:04
     */
    @Override
    public JSONObject paymentBank(ReqStringParam param) {
        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();
        if (order == null) {
            throw new CustomException("订单信息有误");
        }
        if (order.getEndTime() != null && order.getEndTime().isBefore(LocalDateTime.now())) {
            throw new CustomException("订单已过期,请返回重新下单");
        }
        String msg = "下单失败";
        if (order.getOrderType().getValue() == OrderType.RECHARGE.getValue()) {
            msg = "充值失败";
        }
        Map<String, String> sxyPayConfig = sxyPayConfig();
        if (sxyPayConfig == null || sxyPayConfig.size() <= 0) {
            throw new CustomException("支付配置有误");
        }
        ReceiptPaymentBuilder builder = new ReceiptPaymentBuilder(sxyPayConfig.get("merchant_id"));
        builder.setRequestId(order.getOrderSn())
                .setPaymentOrderId(order.getPayId())
                .setKaptchaCode(param.getKaptchaCode());

        ReceiptOrderExecuter executer = new ReceiptOrderExecuter();
        final JSONObject data = new JSONObject();
        try {
            executer.payment(builder, new ResultListenerAdpater() {
                @Override
                public void success(com.alibaba.fastjson15.JSONObject jsonObject) {
                    String result = jsonObject.toJSONString();
                    log.info("下单确认返回数据---------------------" + result);
                    data.put("status", jsonObject.getString("status"));
                    data.put("orderSn", param.getCommon());
                }

                @Override
                public void failure(com.alibaba.fastjson15.JSONObject jsonObject) {
                    log.info("操作失败！{}", jsonObject.toJSONString());
                    data.put("status", jsonObject.getString("status"));
                    if (order.getOrderType().getValue() == OrderType.RECHARGE.getValue()) {
                        data.put("msg", "充值失败");
                    } else {
                        data.put("msg", "下单失败");
                    }
                }
            });
        } catch (ResponseException e) {
            log.error("响应异常</br>" + e.toString());
            throw new CustomException("响应异常");
        } catch (HmacVerifyException e) {
            log.error("签名验证异常</br>" + e.toString());
            throw new CustomException("签名验证异常");
        } catch (RequestException e) {
            log.error("请求异常</br>" + e.toString());
            throw new CustomException("请求异常</br>");
        } catch (UnknownException e) {
            log.error("未知异常</br>" + e.toString());
            throw new CustomException(msg);
        }

        return data;
    }

    @Override
    @Async
    @Lock4j(acquireTimeout = 15000)
    public void noticeSxy(String order, String chnltrxid) throws InterruptedException {
        log.info("================>进入异步线程==>执行支付回调操作:" + LocalDateTime.now());
        MallOrder one = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, order).one();
        if (one == null) {
            return;
        }
        if (one.getStatusUser().getValue() != UserOrderStatus.WAIT_PAY.getValue()) {
            return;
        }
        tradeService.afterPaySuccess(chnltrxid, one);
        log.info("================>退出异步线程:" + LocalDateTime.now());
    }

    @Override
    @Transactional
    public Object adapayAlipayH5(ReqStringParam param) throws Exception {
        Adapay.debug = true;
        Adapay.prodMode = true;//默认为生产模式，false可以使用mock模式
        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();
        if (order.getEndTime() != null && order.getEndTime().isBefore(LocalDateTime.now())) {
            throw new CustomException("订单已过期,请返回重新下单");
        }
        Map<String, String> adapayPayConfig = adapayPayConfig();
        if (adapayPayConfig == null || adapayPayConfig.size() <= 0) {
            throw new CustomException("支付配置有误");
        }
        MerConfig merConfig = new MerConfig();
        merConfig.setApiKey(adapayPayConfig.get("api_key"));
        merConfig.setApiMockKey(adapayPayConfig.get("mock_api_key"));
        merConfig.setRSAPrivateKey(adapayPayConfig.get("rsa_private_key"));
        Adapay.initWithMerConfig(merConfig);
        log.info("=======execute payment begin======={}", merConfig);
        //创建支付对象的参数，全部参数请参考 https://docs.adapay.tech/api/index.html

        // 请求参数
        Map<String, Object> paymentParams = new HashMap<>();
        paymentParams.put("order_no", order.getOrderSn());
        paymentParams.put("pay_amt", order.getActualPrice());
        paymentParams.put("app_id", adapayPayConfig.get("app_id"));
        paymentParams.put("pay_channel", "alipay_wap");//https://docs.adapay.tech/api/appendix.html#id2
        paymentParams.put("goods_title", OrderType.RECHARGE.getDesc());
        paymentParams.put("goods_desc", OrderType.RECHARGE.getDesc());
        paymentParams.put("description", order.getRemark());
        paymentParams.put("notify_url", adapayPayConfig.get("notify_url"));
        if (order.getEndTime() != null) {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
            paymentParams.put("time_expire", dateTimeFormatter.format(order.getEndTime()));
        }
        // 调用创建方法，获取 Payment对象_
        log.info("execute payment param {}", paymentParams);
        Map<String, Object> payment = Payment.create(paymentParams);
        log.info("支付交易，返回参数：" + JSON.toJSONString(payment));
        log.info("=======execute payment end=======");
        if (payment.get("status").equals("succeeded")) {
            order.setPayType(PayType.ALI_PAY);
            order.setPayTime(new Date());
            order.setUpdateTime(LocalDateTime.now());
            // order.setOrderStatus(OrderStatus.WAIT_SHIP);
            iMallOrderService.updateById(order);
            if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
                RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
                rechargeOrder.setPayTime(LocalDateTime.now());
                rechargeOrder.setPayType(order.getPayType());
                rechargeOrderService.updateById(rechargeOrder);
            }

            return payment;
        }

        return payment;
    }

    @Override
    public Object lianLianBankPay(ReqStringParam param) {
        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();
        if (order.getEndTime() != null && order.getEndTime().isBefore(LocalDateTime.now())) {
            throw new CustomException("订单已过期,请返回重新下单");
        }
        long minutes = 5;
        if (order.getOrderType().getValue() == OrderType.SHOP.getValue()) {
            minutes = ChronoUnit.MINUTES.between(LocalDateTime.now(), order.getEndTime());
        }
        log.info("过期时间------" + minutes);
        // 查询用户信息
        MallUser mallUser = mallUserService.lambdaQuery().eq(MallUser::getUuid, order.getUuid()).one();
        if (mallUser == null) {
            throw new CustomException("用户信息有误");
        }
        if (mallUser.getRealName() == null || mallUser.getIdCard() == null) {
            throw new CustomException("请先进行实名认证");
        }
        String goodsName = "充值";
        if (order.getOrderType().compareTo(OrderType.SHOP) == 0) {
            MallGoods goods = iMallGoodsService.getById(order.getGoodsId());
            goodsName = "购买藏品";
            if (goods != null) {
                goodsName = goods.getName();
            }
        }
        Map<String, String> payConfig = lianlianPayConfig();
        if (payConfig == null || payConfig.size() <= 0) {
            throw new CustomException("支付配置有误");
        }
        Map<String, Object> jsonObject = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        jsonObject.put("api_version", 1.0);
        //Map<String,Object> map = new HashMap<>();
        jsonObject.put("sign_type", "RSA");
        // 时间
        jsonObject.put("time_stamp", sdf.format(new Date()));
        // 商户号
        jsonObject.put("oid_partner", payConfig.get("oid_partner"));
        // 用户id
        jsonObject.put("user_id", order.getUuid());
        // 虚拟还是实物   109001  101001
        jsonObject.put("busi_partner", "109001");
        // 订单号
        jsonObject.put("no_order", order.getOrderSn());
        // 下单时间
        jsonObject.put("dt_order", sdf.format(new Date()));
        // 过期时间
        jsonObject.put("valid_order", minutes);
        // 商品名称
        jsonObject.put("name_goods", goodsName);
        // 交易金额
        jsonObject.put("money_order", order.getActualPrice());
        // 回调地址
        jsonObject.put("notify_url", payConfig.get("notify_url"));
        // 返回地址
        jsonObject.put("back_url", payConfig.get("notify_url"));
        // 风控参数
        JSONObject jsonObject1 = new JSONObject();
        // 商品类目
        jsonObject1.put("frms_ware_category", "4007");
        // 用户id
        jsonObject1.put("user_info_mercht_userno", order.getUuid());
        // 手机号码
        jsonObject1.put("user_info_bind_phone", mallUser.getMobile());
        // 注册时间
        jsonObject1.put("user_info_dt_register", sdf.format(new Date()));
        // 商品名称
        jsonObject1.put("goods_name", goodsName);
        // 真实姓名
        jsonObject1.put("user_info_full_name", mallUser.getRealName());
        // 户口类型
        jsonObject1.put("user_info_id_type", 0);
        // 身份证号码
        jsonObject1.put("user_info_id_no", mallUser.getIdCard());
        // 商户是否对用户有实名认证 1-是 0-否
        jsonObject1.put("user_info_identify_state", 1);
        // 实名认证方式。
        //1 - 银行卡认证。
        //2 - 现场认证。
        //3 - 身份证远程认证。
        //4 - 其他认证。
        jsonObject1.put("user_info_identify_type", 4);
        // 风控数据
        jsonObject.put("risk_item", jsonObject1.toJSONString());
        // 支付产品标识。0， 快捷收款。1， 认证收款。2， 网银收款。5， 新认证收款。12， 手机网银收款 。
        jsonObject.put("flag_pay_product", 0);
        // 应用渠道标识。0， App-Android。1， App-iOS。2， Web。3， H5。
        jsonObject.put("flag_chnl", 3);
        Map<String, Object> sortMap = new TreeMap<String, Object>(new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {

                return ((String) o1).compareTo((String) o2);
            }
        });

        sortMap.putAll(jsonObject);
        String s1 = sortMap.toString().replaceAll(", ", "&");
        s1 = s1.substring(1, s1.length() - 1);
        String sign = null;
        try {
            sign = LianSignUtils.sign(s1, payConfig.get("private_key"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (sign == null) {
            throw new CustomException("生成签名异常");
        }
        jsonObject.put("sign", sign);
        JSONObject json = new JSONObject(jsonObject);
        String s = HttpUtils.sendPostV2("https://payserverapi.lianlianpay.com/v1/paycreatebill", json.toJSONString());
        log.info("连连返回数据--------------" + s);
        JSONObject result = JSON.parseObject(s);
        JSONObject data = new JSONObject();
        if (result.getString("ret_code").equals("0000")) {
            //order.setPayType(PayType.FAST_PAYMENT);
            order.setPayTime(new Date());
            order.setUpdateTime(LocalDateTime.now());
            // order.setOrderStatus(OrderStatus.WAIT_SHIP);
            iMallOrderService.updateById(order);
            if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
                RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
                rechargeOrder.setPayTime(LocalDateTime.now());
                rechargeOrderService.updateById(rechargeOrder);
            }

            data.put("redirectUrl", result.getString("gateway_url"));

            return data;
        }

        throw new CustomException(result.getString("ret_msg"));
    }

    @Override
    public JSONObject behalf(AccountWithdrawInfo accountWithdrawInfo, AccountWithdrawAudit accountWithdrawAudit) {
        Map<String, String> payConfig = sxyPayConfig();
        if (payConfig == null || payConfig.size() <= 0) {
            throw new CustomException("支付配置有误");
        }
        SingleOrderBuilder builder = new SingleOrderBuilder(payConfig.get("merchant_id"));
        BigDecimal amount = accountWithdrawAudit.getValue().multiply(BigDecimal.valueOf(100));
        builder.setAmount(amount.intValue() + "").setCurrency("CNY").setRequestId(accountWithdrawAudit.getSn()).setNotifyUrl(payConfig.get("behalf_notify_url")).setRemark("代付");

        TransferDomesticPayee payee = new TransferDomesticPayee();
        payee.setName(accountWithdrawInfo.getCardName());
        payee.setBankCardNum(accountWithdrawInfo.getBankCode());


        builder.setPayee(payee);
        final JSONObject data = new JSONObject();
        TransferDomesticSingleOrderExecuter executer = new TransferDomesticSingleOrderExecuter();
        try {
            executer.bothOrder(builder, new ResultListenerAdpater() {
                @Override
                public void success(com.alibaba.fastjson15.JSONObject jsonObject) {
                    log.info("提交成功</br>{}", jsonObject.toJSONString());
                    data.put("status", "true");
                }

                @Override
                public void failure(com.alibaba.fastjson15.JSONObject jsonObject) {
                    log.info("提交成功</br>,{}", jsonObject.toJSONString());
                    data.put("status", "false");
                }
            });
        } catch (ResponseException e) {
            log.error("响应异常</br>,{}", e.toString());
        } catch (HmacVerifyException e) {
            log.error("签名验证异常</br>,{}", e.toString());
        } catch (RequestException e) {
            log.error("请求异常</br>,{}", e.toString());
        } catch (UnknownException e) {
            log.error("未知异常</br>,{}", e.toString());
        }

        return data;
    }


    /**
     * 实时付款正常流程只需要调用付款申请接口，同步返回0000时指创建连连支付单成功，订单处于付款处理中，等待连连付款结果通知告知付款状态
     *
     * @param accountWithdrawInfo
     * @param accountWithdrawAudit
     * @throws Exception
     */
    @Override
    public boolean behalfLian(AccountWithdrawInfo accountWithdrawInfo, AccountWithdrawAudit accountWithdrawAudit) {
        try {
            Map<String, String> payConfig = lianlianPayConfig();
            if (payConfig == null || payConfig.size() <= 0) {
                throw new CustomException("支付配置有误");
            }
            // 连连内部测试环境数据(商户测试期间需要用正式的数据测试，测试时默认单笔单日单月额度50，等测试OK，申请走上线流程打开额度）
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            PaymentRequestBean paymentRequestBean = new PaymentRequestBean();
            paymentRequestBean.setNo_order(accountWithdrawAudit.getSn());
            paymentRequestBean.setDt_order(sdf.format(new Date()));
            paymentRequestBean.setMoney_order(accountWithdrawAudit.getValue() + "");
            paymentRequestBean.setCard_no(accountWithdrawInfo.getBankCode());
            // paymentRequestBean.setCard_no("6232632000102254611");
            paymentRequestBean.setAcct_name(accountWithdrawInfo.getCardName());
            // paymentRequestBean.setAcct_name("深圳市一加凌科技有限公司");
            // paymentRequestBean.setBank_name("中国平安银行");
            paymentRequestBean.setInfo_order("提现");
            //paymentRequestBean.setBank_code("01040000");
            paymentRequestBean.setFlag_card("0");

            paymentRequestBean.setMemo("代付");
            // 填写商户自己的接收付款结果回调异步通知
            paymentRequestBean.setNotify_url(payConfig.get("behalf_notify_url"));
            paymentRequestBean.setOid_partner(payConfig.get("oid_partner"));
            // paymentRequestBean.setPlatform("http://106.14.165.16");
            paymentRequestBean.setApi_version("1.0");
            paymentRequestBean.setSign_type("RSA");
            // 用商户自己的私钥加签
            String signData = genSignData(JSON.parseObject(JSON.toJSONString(paymentRequestBean)));
            String sign = LianSignUtils.sign(signData, payConfig.get("private_key"));
            paymentRequestBean.setSign(sign);

            String jsonStr = JSON.toJSONString(paymentRequestBean);
            log.info("实时付款请求报文：" + jsonStr);
            // 用银通公钥对请求参数json字符串加密
            // 报Illegal sign key
            // size异常时，可参考这个网页解决问题http://www.wxdl.cn/java/security-invalidkey-exception.html
            String encryptStr = LianLianPaySecurity.encrypt(jsonStr, payConfig.get("publick_key"));
            //	System.out.print("实时付款接口加密请求报文：" + encryptStr);
            if (StringUtils.isEmpty(encryptStr)) {
                // 加密异常
                log.error("加密异常:");
                return false;
            }

            JSONObject json = new JSONObject();
            json.put("oid_partner", "202206170003276003");
            json.put("pay_load", encryptStr);
            String response = HttpUtils.sendPostV2("https://instantpay.lianlianpay.com/paymentapi/payment.htm", json.toJSONString());
            log.info("付款接口返回响应报文：" + response);
            if (StringUtils.isEmpty(response)) {
                // 出现异常时调用订单查询，明确订单状态，不能私自设置订单为失败状态，以免造成这笔订单在连连付款成功了，而商户设置为失败
                queryPaymentAndDealBusiness(paymentRequestBean.getNo_order(), accountWithdrawAudit);
            } else {
                PaymentResponseBean paymentResponseBean = JSONObject.parseObject(response, PaymentResponseBean.class);

                // 对返回0000时验证签名
                if (paymentResponseBean.getRet_code().equals("0000")) {
                    boolean signCheck = LianSignUtils.verify(genSignData(JSONObject.parseObject(response)), payConfig.get("publick_key"), paymentResponseBean.getSign());
                    if (!signCheck) {
                        // 传送数据被篡改，可抛出异常，再人为介入检查原因
                        log.error("返回结果验签异常,可能数据被篡改");
                        return true;
                    }
                    log.info(paymentRequestBean.getNo_order() + "订单处于付款处理中");
                    // 已生成连连支付单，付款处理中（交易成功，不是指付款成功，是指跟连连流程正常），商户可以在这里处理自已的业务逻辑（或者不处理，在异步回调里处理逻辑）,最终的付款状态由异步通知回调告知
                } else if (paymentResponseBean.getRet_code().equals("4002")
                        || paymentResponseBean.getRet_code().equals("4004")) {
                    // 当调用付款申请接口返回4002，4003，4004,会同时返回验证码，用于确认付款接口
                    // 对于疑似重复订单，需先人工审核这笔订单是否正常的付款请求，而不是系统产生的重复订单，确认后再调用确认付款接口或者在连连商户站后台操作疑似订单，api不调用确认付款接口
                    // 对于疑似重复订单，也可不做处理，
                    accountWithdrawAudit.setRemarks("疑似重复订单，请前往连连平台进行人工审核");
                } else if (RetCodeEnum.isNeedQuery(paymentResponseBean.getRet_code())) {
                    // 出现1002，2005，4006，4007，4009，9999这6个返回码时（或者对除了0000之后的code都查询一遍查询接口）调用付款结果查询接口，明确订单状态，不能私自设置订单为失败状态，以免造成这笔订单在连连付款成功了，而商户设置为失败
                    // 第一次测试对接时，返回{"ret_code":"4007","ret_msg":"敏感信息解密异常"},可能原因报文加密用的公钥改动了,demo中的公钥是连连公钥，商户生成的公钥用于上传连连商户站用于连连验签，生成的私钥用于加签
                    queryPaymentAndDealBusiness(paymentRequestBean.getNo_order(), accountWithdrawAudit);
                } else {
                    // 返回其他code时，可将订单置为失败
                    return false;
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException("连连代付异常");
        }

    }

    /**
     * 生成待签名串
     * paramMap
     *
     * @param
     * @return
     */
    public static String genSignData(JSONObject jsonObject) {
        StringBuffer content = new StringBuffer();

        // 按照key做首字母升序排列
        List<String> keys = new ArrayList<String>(jsonObject.keySet());
        Collections.sort(keys, String.CASE_INSENSITIVE_ORDER);
        for (int i = 0; i < keys.size(); i++) {
            String key = (String) keys.get(i);
            // sign 和ip_client 不参与签名
            if ("sign".equals(key)) {
                continue;
            }
            String value = (String) jsonObject.getString(key);
            // 空串不参与签名
            if (org.apache.commons.lang3.StringUtils.isEmpty(value)) {
                continue;
            }
            content.append((i == 0 ? "" : "&") + key + "=" + value);

        }
        String signSrc = content.toString();
        if (signSrc.startsWith("&")) {
            signSrc = signSrc.replaceFirst("&", "");
        }
        return signSrc;
    }

    // 异常时，先查询订单状态，再根据订单状态处理业务逻辑
    public void queryPaymentAndDealBusiness(String orderNo, AccountWithdrawAudit accountWithdrawAudit) throws Exception {
        // 连连内部测试环境数据
        Map<String, String> payConfig = lianlianPayConfig();
        if (payConfig == null || payConfig.size() <= 0) {
            throw new CustomException("支付配置有误");
        }
        QueryPaymentRequestBean queryRequestBean = new QueryPaymentRequestBean();
        queryRequestBean.setNo_order(orderNo);
        queryRequestBean.setOid_partner(payConfig.get("oid_partner"));
        // queryRequestBean.setPlatform("test.com");
        queryRequestBean.setApi_version("1.0");
        queryRequestBean.setSign_type("RSA");
        // 用商户自己的私钥加签
        String signData = genSignData(JSON.parseObject(JSON.toJSONString(queryRequestBean)));
        String sign = null;

        sign = LianSignUtils.sign(signData, payConfig.get("private_key"));


        queryRequestBean.setSign(sign);
        String queryResult = HttpUtils.sendPostV2("https://instantpay.lianlianpay.com/paymentapi/queryPayment.htm",
                JSON.toJSONString(queryRequestBean));
        log.info("实时付款查询接口响应报文：" + queryResult);
        if (StringUtils.isEmpty(queryResult)) {
            // 可抛异常，查看原因
            log.error("实时付款查询接口响应异常");
            return;
        }
        QueryPaymentResponseBean queryPaymentResponseBean = JSONObject.parseObject(queryResult,
                QueryPaymentResponseBean.class);
        boolean signCheck = LianSignUtils.verify(genSignData(JSONObject.parseObject(queryResult)), payConfig.get("publick_key"), queryPaymentResponseBean.getSign());
        if (!signCheck) {
            // 传送数据被篡改，可抛出异常，再人为介入检查原因
            log.error("返回结果验签异常,可能数据被篡改");
            return;
        }
        if (queryPaymentResponseBean.getRet_code().equals("0000")) {
            PaymentStatusEnum paymentStatusEnum = PaymentStatusEnum
                    .getPaymentStatusEnumByValue(queryPaymentResponseBean.getResult_pay());
            BalanceChange balanceChange = balanceChangeService.getById(accountWithdrawAudit.getBalanceId());
            MallUser one = mallUserService.lambdaQuery().eq(MallUser::getUuid, balanceChange.getUuid()).one();
            // TODO商户根据订单状态处理自已的业务逻辑
            switch (paymentStatusEnum) {
                case PAYMENT_APPLY:
                    // 付款申请，这种情况一般不会发生，如出现，请直接找连连技术处理
                    break;
                case PAYMENT_CHECK:
                    // 返回4002，4003，4004时，订单会处于复核状态，这时还未创建连连支付单，没提交到银行处理，如需对该订单继续处理，需商户先人工审核这笔订单是否是正常的付款请求，没问题后再调用确认付款接口
                    // 如果对于复核状态的订单不做处理，可当做失败订单
                    accountWithdrawAudit.setRemarks("疑似重复订单，请前往连连平台进行人工审核");
                    break;
                case PAYMENT_SUCCESS:
                    // 转账成功
                    accountWithdrawAudit.setReceiptStatus(1);
                    accountWithdrawAudit.setUpdateTime(LocalDateTime.now());
                    accountWithdrawAudit.setPaySn(queryPaymentResponseBean.getOid_paybill());

                    break;
                case PAYMENT_FAILURE:
                    // 将余额加入
                    rabbitUtils.sendBalanceMessage(accountWithdrawAudit.getUuid(), balanceChange.getChangAmount().abs(), "1", BalanceBusinessType.WITHDRAW_FAIL, "提现驳回", balanceChange.getId() + "", BalanceTypeEnum.BALANCE);


                    // 转账失败
                    accountWithdrawAudit.setReceiptStatus(2);
                    accountWithdrawAudit.setUpdateTime(LocalDateTime.now());
                    accountWithdrawAudit.setRemarks(queryPaymentResponseBean.getMemo());
                    accountWithdrawAudit.setPaySn(queryPaymentResponseBean.getOid_paybill());

                    break;
                case PAYMENT_DEALING:
                    break;
                case PAYMENT_RETURN:
                    // 可当做失败（退款情况
                    // 极小概率下会发生，个别银行处理机制是先扣款后打款给用户时再检验卡号信息是否正常，异常时会退款到连连商户账上）
                    break;
                case PAYMENT_CLOSED:
                    break;
                default:
                    break;
            }
        } else if (queryPaymentResponseBean.getRet_code().equals("8901")) {
            // 订单不存在，这种情况可以用原单号付款，最好不要换单号，如换单号，在连连商户站确认下改订单是否存在，避免系统并发时返回8901，实际有一笔订单
        } else {
            // 查询异常（极端情况下才发生,对于这种情况，可人工介入查询，在连连商户站查询或者联系连连客服，查询订单状态）
            log.error("查询异常");
        }

    }


    @Override
    public JSONObject sandPayCreateOrderBank(String orderSn) {
        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, orderSn).one();

        String remarks = "充值";
        if (order.getOrderType().compareTo(OrderType.SHOP) == 0) {
            MallGoods goods = iMallGoodsService.getById(order.getGoodsId());
            if (goods == null) {
                throw new CustomException("订单数据错误");
            }
            remarks = goods.getName();
        }
        String sdNotifyUrl = sysDictDataService.getObjectData(SandSetting.class).getNotifyUrl();
        SandSetting sandSetting = sysDictDataService.getObjectData(SandSetting.class);
        // 组后台报文
        JSONObject head = new JSONObject();
        head.put("version", "1.0");
        head.put("method", "sandPay.fastPay.quickPay.index");
        head.put("productId", "00000016");
        head.put("accessType", "1");
        head.put("mid", sandSetting.getMid());
        head.put("channelType", "08");
        head.put("reqTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        // String formatAmount = new DecimalFormat("000000000000").format(order.getActualPrice().multiply(BigDecimal.valueOf(100)).longValue());
        String formatAmount = yuanToFen(order.getActualPrice().doubleValue());
        JSONObject body = new JSONObject();
        body.put("userId", order.getUuid());
        //body.put("clearCycle", map.get("clearCycle"));
        body.put("currencyCode", 156);
        body.put("frontUrl", sdNotifyUrl);
        body.put("notifyUrl", sdNotifyUrl);
        body.put("orderCode", orderSn);
        body.put("orderTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        body.put("totalAmount", formatAmount);
        body.put("body", remarks);
        body.put("subject", remarks);
        //body.put("extend", map.get("extend"));

        JSONObject data = new JSONObject();
        data.put("head", head);
        data.put("body", body);
        try {
            // 报文签名
            String reqSign = digitalSignShanDe(data.toJSONString());
            JSONObject respJson = new JSONObject();
            respJson.put("data", JSON.toJSONString(data));
            respJson.put("sign", reqSign);
            log.info("杉德请求数据-------------" + respJson.toJSONString());
            order.setPayType(PayType.FAST_PAYMENT);
            order.setPayTime(new Date());
            order.setUpdateTime(LocalDateTime.now());
//             order.setOrderStatus(OrderStatus.WAIT_SHIP);
            iMallOrderService.updateById(order);
            if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
                RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
                rechargeOrder.setPayTime(LocalDateTime.now());
                // rechargeOrder.setPayType(PayType.FAST_PAYMENT);
                rechargeOrderService.updateById(rechargeOrder);
            }

            return respJson;
        } catch (Exception e) {
            log.error("CashierPayServlet post error <<<", e);
        }
        return null;
    }

    public static String yuanToFen(double price) {
        DecimalFormat df = new DecimalFormat("#.00");
        price = Double.valueOf(df.format(price));
        int money = (int) (price * 100);
        String moneyStr = String.valueOf(money);
        while (true) {
            if (moneyStr.length() < 12) {
                moneyStr = "0" + moneyStr;
            } else {
                break;
            }
        }
        return moneyStr;
    }


    @Override
    public Map<String, String> sandPayNoticeBank(Map<String, String> map) {
        String data = map.get("data");
        String sign = map.get("sign");
        // 验证签名
        boolean valid;
        try {

            Map<String, String> resultMap = new HashMap<>(1);
            resultMap.put("respCode", "000000");
            SandSetting sandSetting = sysDictDataService.getObjectData(SandSetting.class);
            valid = CryptoUtil.verifyDigitalSign(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), data.getBytes(StandardCharsets.UTF_8), org.apache.commons.codec.binary.Base64.decodeBase64(sign),
                    CertUtil.getPublicKey(), "SHA1WithRSA");
            // 验签失败
            if (valid) {
                log.info("verify sign success");
                JSONObject dataJson = JSONObject.parseObject(data);
                if (dataJson != null) {
                    // 成功
                    log.info("后台通知业务数据为：" + JSONObject.toJSONString(dataJson, true));
                    dataJson = dataJson.getJSONObject("body");
                    String orderSn = dataJson.getString("orderCode");
                    MallOrder one = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, orderSn).one();
                    if (one.getStatusUser().getValue() != UserOrderStatus.WAIT_PAY.getValue() || !"1".equals(dataJson.getString("orderStatus"))) {
                        return resultMap;
                    }
                    String externalProductCode = dataJson.getString("externalProductCode");
                    if ("00000016".equals(externalProductCode)) {
                        // one.setPayType(PayType.FAST_PAYMENT);
                    }
                    Date payTime = DateUtils.parseDate(dataJson.getString("payTime"));
                    one.setPayTime(payTime);
                    tradeService.afterPaySuccess(dataJson.getString("tradeNo"), one);
                    return resultMap;
                }
            }

        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 发送支付短信 杉德
     *
     * @param param
     * @return 结果
     * @Author lx
     * @Date: 2022/07/04 01:44
     */
    @Override
    public Object sandGetKaptcha(@NotNull ReqStringParam param) {
        AccountWithdrawInfo accountWithdrawInfo = accountWithdrawInfoService.lambdaQuery().eq(AccountWithdrawInfo::getBindCardId, param.getBandCartId()).one();
        if (accountWithdrawInfo == null) {
            throw new CustomException("支付账号信息有误");
        }
        SandSetting sandSetting = sysDictDataService.getObjectData(SandSetting.class);
        // 组后台报文
        JSONObject head = new JSONObject();
        head.put("version", "1.0");
        head.put("method", "sandPay.fastPay.common.sms");
        head.put("productId", "00000018");
        head.put("accessType", "1");
        head.put("mid", sandSetting.getMid());
        head.put("channelType", "08");
        head.put("reqTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        JSONObject body = new JSONObject();
        body.put("userId", accountWithdrawInfo.getUserId());
        body.put("orderCode", param.getCommon());
        body.put("phoneNo", accountWithdrawInfo.getBankTelPhone());
        body.put("bid", accountWithdrawInfo.getBindCardId());
        JSONObject data = new JSONObject();
        data.put("head", head);
        data.put("body", body);
        JSONObject resultData = new JSONObject();
        try {
            // 报文签名
            String reqSign = PayServiceImpl.digitalSignShanDe(data.toJSONString());
            //整体报文格式
            Map<String, String> reqMap = new HashMap<String, String>();
            reqMap.put("charset", "UTF-8");
            reqMap.put("data", JSON.toJSONString(data));
            reqMap.put("signType", "01");
            reqMap.put("sign", reqSign);
            reqMap.put("extend", "");

            log.info("请求报文----数据：\n" + JSONObject.toJSONString(JSON.toJSONString(data)));
            log.info("请求报文----签名：\n" + JSONObject.toJSONString(reqSign));
            String result = HttpClient.doPost(sandSetting.getSandUrl() + "/fastPay/apiPay/sms", reqMap, 300000, 600000);
            result = URLDecoder.decode(result, "UTF-8");
            log.info("响应报文：\n" + result);
            Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
            String respData = respMap.get("data");
            JSONObject jsonObject = JSONObject.parseObject(respData);
            String body1 = jsonObject.getString("head");
            if (org.apache.commons.lang3.StringUtils.isNotEmpty(body1)) {
                JSONObject object = JSONObject.parseObject(body1);
                if (!object.getString("respCode").equals("000000")) {
                    throw new CustomException("验证码发送失败，请稍后重试");
                }
                resultData.put("outTradeNo", param.getCommon());
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new CustomException(e.getMessage());
        }

        return resultData;
    }

    /**
     * 银行卡支付 杉德
     *
     * @param param
     * @return 结果
     * @Author lx
     * @Date: 2022/07/04 01:44
     */
    @Override
    public Object sandPay(ReqStringParam param) {
        AccountWithdrawInfo accountWithdrawInfo = accountWithdrawInfoService.lambdaQuery().eq(AccountWithdrawInfo::getBindCardId, param.getBandCartId()).one();
        if (accountWithdrawInfo == null) {
            throw new CustomException("支付账号信息有误");
        }
        MallOrder order = iMallOrderService.lambdaQuery().eq(MallOrder::getOrderSn, param.getCommon()).one();
        if (order.getEndTime() != null && order.getEndTime().isBefore(LocalDateTime.now())) {
            throw new CustomException("订单已过期,请返回重新下单");
        }
        String remarks = "充值";
        if (order.getOrderType().compareTo(OrderType.SHOP) == 0) {
            MallGoods goods = iMallGoodsService.getById(order.getGoodsId());
            if (goods == null) {
                throw new CustomException("订单数据错误");
            }
            remarks = goods.getName();
        }
        SandSetting sandSetting = sysDictDataService.getObjectData(SandSetting.class);
        String sdNotifyUrl = sandSetting.getNotifyUrl();
        // 组后台报文
        JSONObject head = new JSONObject();
        head.put("version", "1.0");
        head.put("method", "sandPay.fastPay.apiPay.pay");
        head.put("productId", "00000018");
        head.put("accessType", "1");
        head.put("mid", sandSetting.getMid());
        head.put("channelType", "08");
        head.put("reqTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        JSONObject body = new JSONObject();
        String formatAmount = yuanToFen(order.getActualPrice().doubleValue());
        body.put("userId", accountWithdrawInfo.getUserId());
        body.put("orderCode", param.getCommon());
        body.put("phoneNo", accountWithdrawInfo.getBankTelPhone());
        body.put("bid", accountWithdrawInfo.getBindCardId());
        body.put("smsCode", param.getKaptchaCode());
        body.put("currencyCode", 156);
        body.put("notifyUrl", sdNotifyUrl);
        body.put("orderTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        body.put("totalAmount", formatAmount);
        body.put("body", remarks);
        body.put("subject", remarks);
        JSONObject data = new JSONObject();
        data.put("head", head);
        data.put("body", body);
        JSONObject resultData = new JSONObject();
        try {
            // 报文签名
            String reqSign = PayServiceImpl.digitalSignShanDe(data.toJSONString());
            //整体报文格式
            Map<String, String> reqMap = new HashMap<String, String>();
            reqMap.put("charset", "UTF-8");
            reqMap.put("data", JSON.toJSONString(data));
            reqMap.put("signType", "01");
            reqMap.put("sign", reqSign);
            reqMap.put("extend", "");

            log.info("请求报文----数据：\n" + JSONObject.toJSONString(JSON.toJSONString(data)));
            log.info("请求报文----签名：\n" + JSONObject.toJSONString(reqSign));
            String result = HttpClient.doPost(sandSetting.getSandUrl() + "/fastPay/apiPay/pay", reqMap, 300000, 600000);
            result = URLDecoder.decode(result, "UTF-8");
            log.info("响应报文：\n" + result);
            Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
            String respData = respMap.get("data");
            JSONObject jsonObject = JSONObject.parseObject(respData);
            String body1 = jsonObject.getString("head");
            if (org.apache.commons.lang3.StringUtils.isNotEmpty(body1)) {
                JSONObject object = JSONObject.parseObject(body1);
                if (!object.getString("respCode").equals("000000")) {
                    throw new CustomException("支付失败，请重新下单");
                }
                // order.setPayType(PayType.FAST_PAYMENT);
                order.setPayTime(new Date());
                order.setUpdateTime(LocalDateTime.now());
                // order.setOrderStatus(OrderStatus.WAIT_SHIP);
                iMallOrderService.updateById(order);
                if (order.getOrderType().compareTo(OrderType.RECHARGE) == 0) {
                    RechargeOrder rechargeOrder = rechargeOrderService.lambdaQuery().eq(RechargeOrder::getOrderSn, order.getOrderSn()).one();
                    rechargeOrder.setPayTime(LocalDateTime.now());
                    //rechargeOrder.setPayType(PayType.FAST_PAYMENT);
                    rechargeOrderService.updateById(rechargeOrder);
                }
                resultData.put("payInfo", jsonObject);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new CustomException(e.getMessage());
        }

        return resultData;
    }

    public boolean sandBalance(AccountWithdrawAudit accountWithdrawAudit) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = accountWithdrawAudit.getAuditTime().atZone(zoneId);
        Date date = Date.from(zdt.toInstant());

        String format = new SimpleDateFormat("yyyyMMddHHmmss").format(date);
        String formatAmount = yuanToFen(accountWithdrawAudit.getValue().doubleValue());
        // 组后台报文
        JSONObject request = new JSONObject();
        request.put("version", "01");
        request.put("productId", "00000004");
        request.put("tranTime", format);
        request.put("orderCode", accountWithdrawAudit.getSn());
        request.put("channelType", "");
        request.put("extend", "");

        log.info("请求数据：\n" + request.toJSONString());
        try {
            String aesKey = RandomStringGenerator.getRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes("UTF-8");

            byte[] plainBytes = request.toJSONString().getBytes("UTF-8");
            // 参数加密
            String encryptData = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
                            "AES/ECB/PKCS5Padding", null)),
                    "UTF-8");
            SandSetting sandSetting = sysDictDataService.getObjectData(SandSetting.class);
            // 报文签名
            // String reqSign = PayServiceImpl.digitalSignShanDe(request.toJSONString());
            String sign = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.digitalSign(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), plainBytes, CertUtil.getPrivateKey(),
                            "SHA1WithRSA")), "UTF-8");
            // 公钥加密
            String encryptKey = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.RSAEncrypt(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
                            "RSA/ECB/PKCS1Padding")), "UTF-8");
            Map<String, String> reqMap = new HashMap<String, String>();
            //整体报文格式
            reqMap.put("transCode", "MBQU"); // 交易码
            reqMap.put("accessType", "0"); // 接入类型
            reqMap.put("merId", sandSetting.getMid()); // 合作商户ID	杉德系统分配，唯一标识
            reqMap.put("plId", "");  // 平台商户ID	平台接入必填，商户接入为空
            reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
            reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
            reqMap.put("sign", sign); // 签名
            reqMap.put("extend", ""); // 扩展域

            log.info("请求报文：\n" + reqMap);
            String result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi/queryBalance", reqMap, 300000, 600000);
            result = URLDecoder.decode(result, "UTF-8");
            log.info("响应报文：\n" + result);
            Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

            String retEncryptKey = (String) responseMap.get("encryptKey");
            String retEncryptData = (String) responseMap.get("encryptData");
            String retSign = (String) responseMap.get("sign");

            log.info("retEncryptKey:[" + retEncryptKey + "]");
            log.info("retEncryptData:[" + retEncryptData + "]");
            log.info("retSign:[" + retSign + "]");

            byte[] decodeBase64KeyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retEncryptKey
                    .getBytes("UTF-8"));

            byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(),
                    decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                    "RSA/ECB/PKCS1Padding");

            byte[] decodeBase64DataBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retEncryptData
                    .getBytes("UTF-8"));

            byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                    merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

            String respData = new String(respDataBytes, "UTF-8");
            log.info("retData:[" + respData + "]");

            byte[] signBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retSign
                    .getBytes("UTF-8"));

            boolean isValid = CryptoUtil.verifyDigitalSign(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), respDataBytes, signBytes,
                    CertUtil.getPublicKey(), "SHA1WithRSA");

            if (isValid) {
                JSONObject object = JSONObject.parseObject(respData);
                if (object.getString("respCode").equals("0000") && object.getString("balance") != null) {
                    String balance = object.getString("balance");
                    if (Long.valueOf(balance) < Long.valueOf(formatAmount)) {
                        throw new CustomException("余额不足");
                    }
                    return true;
                }
                return false;
            }

            return false;
        } catch (Exception e) {
            // log.error(e.getMessage());
            throw new CustomException(e.getMessage());
        }
    }

    /**
     * 描述信息
     *
     * @param accountWithdrawInfo
     * @param accountWithdrawAudit
     * @return 结果
     * @Author lx
     * @Date: 2022/07/25 09:37
     */
    @Override
    public boolean sandBehalf(AccountWithdrawInfo accountWithdrawInfo, AccountWithdrawAudit accountWithdrawAudit) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = accountWithdrawAudit.getAuditTime().atZone(zoneId);
        Date date = Date.from(zdt.toInstant());
        String format = new SimpleDateFormat("yyyyMMddHHmmss").format(date);
        String formatAmount = yuanToFen(accountWithdrawAudit.getValue().doubleValue());
        // 组后台报文
        JSONObject request = new JSONObject();
        request.put("version", "01");                                            //版本号
        request.put("productId", "00000004");                                   //产品ID
        request.put("tranTime", format);                                        //交易时间
        request.put("orderCode", accountWithdrawAudit.getSn());                 //订单号
        request.put("timeOut", DateUtils.getNextDayTime(3));                    //订单超时时间
        request.put("tranAmt", formatAmount);                                   //金额
        request.put("currencyCode", "156");                                     //币种
        request.put("accAttr", "0");                                            //账户属性     0-对私   1-对公
        request.put("accType", "4");                                            //账号类型      3-公司账户  4-银行卡
        request.put("accNo", accountWithdrawInfo.getBankCode());                //收款人账户号
        request.put("accName", accountWithdrawInfo.getCardName());              //收款人账户名
        request.put("remark", "消费");                                            //摘要

        log.info("请求数据：\n" + request.toJSONString());
        try {
            String aesKey = RandomStringGenerator.getRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes("UTF-8");

            byte[] plainBytes = request.toJSONString().getBytes("UTF-8");
            // 参数加密
            String encryptData = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
                            "AES/ECB/PKCS5Padding", null)),
                    "UTF-8");
            // 报文签名
            // String reqSign = PayServiceImpl.digitalSignShanDe(request.toJSONString());
            SandSetting sandSetting = sysDictDataService.getObjectData(SandSetting.class);
            String sign = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.digitalSign(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), plainBytes, CertUtil.getPrivateKey(),
                            "SHA1WithRSA")), "UTF-8");
            // 公钥加密
            String encryptKey = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.RSAEncrypt(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
                            "RSA/ECB/PKCS1Padding")), "UTF-8");
            Map<String, String> reqMap = new HashMap<String, String>();
            //整体报文格式
            reqMap.put("transCode", "RTPM"); // 交易码
            reqMap.put("accessType", "0"); // 接入类型
            reqMap.put("merId", sandSetting.getMid()); // 合作商户ID	杉德系统分配，唯一标识
            reqMap.put("plId", "");  // 平台商户ID	平台接入必填，商户接入为空
            reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
            reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
            reqMap.put("sign", sign); // 签名
            reqMap.put("extend", ""); // 扩展域

            log.info("请求报文：\n" + reqMap);
            String result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi/agentpay", reqMap, 300000, 600000);
            result = URLDecoder.decode(result, "UTF-8");
            log.info("响应报文：\n" + result);
            Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

            String retEncryptKey = (String) responseMap.get("encryptKey");
            String retEncryptData = (String) responseMap.get("encryptData");
            String retSign = (String) responseMap.get("sign");

            log.info("retEncryptKey:[" + retEncryptKey + "]");
            log.info("retEncryptData:[" + retEncryptData + "]");
            log.info("retSign:[" + retSign + "]");

            byte[] decodeBase64KeyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retEncryptKey
                    .getBytes("UTF-8"));

            byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(),
                    decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                    "RSA/ECB/PKCS1Padding");

            byte[] decodeBase64DataBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retEncryptData
                    .getBytes("UTF-8"));

            byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                    merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

            String respData = new String(respDataBytes, "UTF-8");
            log.info("retData:[" + respData + "]");

            byte[] signBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retSign
                    .getBytes("UTF-8"));

            boolean isValid = CryptoUtil.verifyDigitalSign(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), respDataBytes, signBytes,
                    CertUtil.getPublicKey(), "SHA1WithRSA");

            if (isValid) {
                log.info("verify sign sucess.");
                JSONObject object = JSONObject.parseObject(respData);
                if (org.apache.commons.lang3.StringUtils.isNotEmpty(object.toJSONString())) {
                    if (object.getInteger("resultFlag") == 0) {
                        // 转账成功
                        accountWithdrawAudit.setReceiptStatus(1);
                        accountWithdrawAudit.setUpdateTime(LocalDateTime.now());
                        accountWithdrawAudit.setPaySn(object.getString("sandSerial"));

                        return true;
                    } else if (object.getInteger("resultFlag") == 1) {
                        // 转账失败
                        throw new CustomException(object.getString("respDesc"));
                    } else if (object.getInteger("resultFlag") == 2) {
                        // 处理中
                        //给延迟队列发送消息
                        accountWithdrawAudit.setRemarks(object.getString("respDesc"));
                        long delayTimes = 5 * 1000;
                        accountWithdrawAudit.setQueryNum(1);
                        amqpTemplate.convertAndSend(QueueEnum.QUEUE_DELAYED_SAND_BEHALF.getExchange(), QueueEnum.QUEUE_DELAYED_SAND_BEHALF.getRouteKey(), accountWithdrawAudit, a -> {
                            a.getMessageProperties().setDelay(Math.toIntExact(delayTimes));
                            return a;
                        });
                        log.info("send delay message sandQuery:{}", accountWithdrawAudit.getSn());
                    }

                    return true;
                }
            }

            return false;
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new CustomException(e.getMessage());
        }
    }

    public void sandBehalfQuery(AccountWithdrawAudit accountWithdrawAudit) {
        if (accountWithdrawAudit.getReceiptStatus() != 0) {
            log.info("转账状态为----------" + accountWithdrawAudit.getReceiptStatus());
            return;
        }
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = accountWithdrawAudit.getAuditTime().atZone(zoneId);
        Date date = Date.from(zdt.toInstant());

        String format = new SimpleDateFormat("yyyyMMddHHmmss").format(date);
        // 组后台报文
        JSONObject request = new JSONObject();
        request.put("version", "01");                                //版本号
        request.put("productId", "00000004");                       //产品ID
        request.put("tranTime", format);                            //交易时间
        request.put("orderCode", accountWithdrawAudit.getSn());     //订单号
        request.put("extend", "");                                  // 扩展域

        log.info("请求数据：\n" + request.toJSONString());
        try {
            String aesKey = RandomStringGenerator.getRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes("UTF-8");

            byte[] plainBytes = request.toJSONString().getBytes("UTF-8");
            String encryptData = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
                            "AES/ECB/PKCS5Padding", null)),
                    "UTF-8");
            // 报文签名
            // String reqSign = PayServiceImpl.digitalSignShanDe(request.toJSONString());
            SandSetting sandSetting = sysDictDataService.getObjectData(SandSetting.class);
            String sign = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.digitalSign(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), plainBytes, CertUtil.getPrivateKey(),
                            "SHA1WithRSA")), "UTF-8");

            String encryptKey = new String(org.apache.commons.codec.binary.Base64.encodeBase64(
                    CryptoUtil.RSAEncrypt(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
                            "RSA/ECB/PKCS1Padding")), "UTF-8");
            Map<String, String> reqMap = new HashMap<String, String>();
            //整体报文格式
            reqMap.put("transCode", "ODQU"); // 交易码
            reqMap.put("accessType", "0"); // 接入类型
            reqMap.put("merId", sandSetting.getMid()); // 合作商户ID	杉德系统分配，唯一标识
            reqMap.put("plId", "");  // 平台商户ID	平台接入必填，商户接入为空
            reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
            reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
            reqMap.put("sign", sign); // 签名
            reqMap.put("extend", ""); // 扩展域

            log.info("请求报文：\n" + reqMap);
            String result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi/queryOrder", reqMap, 300000, 600000);
            result = URLDecoder.decode(result, "UTF-8");
            log.info("响应报文：\n" + result);
            Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

            String retEncryptKey = (String) responseMap.get("encryptKey");
            String retEncryptData = (String) responseMap.get("encryptData");
            String retSign = (String) responseMap.get("sign");

            log.debug("retEncryptKey:[" + retEncryptKey + "]");
            log.debug("retEncryptData:[" + retEncryptData + "]");
            log.debug("retSign:[" + retSign + "]");

            byte[] decodeBase64KeyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retEncryptKey
                    .getBytes("UTF-8"));

            byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(),
                    decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                    "RSA/ECB/PKCS1Padding");

            byte[] decodeBase64DataBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retEncryptData
                    .getBytes("UTF-8"));

            byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                    merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

            String respData = new String(respDataBytes, "UTF-8");
            log.info("retData:[" + respData + "]");

            byte[] signBytes = org.apache.commons.codec.binary.Base64.decodeBase64(retSign
                    .getBytes("UTF-8"));

            boolean isValid = CryptoUtil.verifyDigitalSign(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), respDataBytes, signBytes,
                    CertUtil.getPublicKey(), "SHA1WithRSA");

            if (isValid) {
                log.error("verify sign sucess.");
                JSONObject object = JSONObject.parseObject(respData);
                if (org.apache.commons.lang3.StringUtils.isNotEmpty(object.toJSONString())) {
                    BalanceChange balanceChange = balanceChangeService.getById(accountWithdrawAudit.getBalanceId());
                    MallUser one = mallUserService.lambdaQuery().eq(MallUser::getUuid, balanceChange.getUuid()).one();
                    log.info("杉德结果状态:resultFlag" + object.getInteger("resultFlag"));
                    if (object.getInteger("resultFlag") == null) {
                        accountWithdrawAudit.setRemarks(object.getString("respDesc"));
                        accountWithdrawAuditMapper.updateById(accountWithdrawAudit);

                        return;
                    }
                    if (object.getInteger("resultFlag") == 0) {
                        // 转账成功
                        accountWithdrawAudit.setReceiptStatus(1);
                        accountWithdrawAudit.setUpdateTime(LocalDateTime.now());
                        accountWithdrawAudit.setPaySn(object.getString("sandSerial"));

                        accountWithdrawAuditMapper.updateById(accountWithdrawAudit);
                    } else if (object.getInteger("resultFlag") == 1) {
                        // 转账失败
                        // 将余额加入
                        rabbitUtils.sendBalanceMessage(accountWithdrawAudit.getUuid(), balanceChange.getChangAmount().abs(), "1", BalanceBusinessType.WITHDRAW_FAIL, "提现驳回", balanceChange.getId() + "", BalanceTypeEnum.BALANCE);

                        accountWithdrawAudit.setReceiptStatus(2);
                        accountWithdrawAudit.setUpdateTime(LocalDateTime.now());
                        accountWithdrawAudit.setRemarks(object.getString("origRespDesc"));
                        accountWithdrawAudit.setPaySn(object.getString("sandSerial"));

                        accountWithdrawAuditMapper.updateById(accountWithdrawAudit);
                    } else if (object.getInteger("resultFlag") == 2) {
                        // 处理中
                        //给延迟队列发送消息
                        Integer queryNum = accountWithdrawAudit.getQueryNum();
                        if (queryNum == null) {
                            queryNum = 1;
                        }
                        Integer time = times[queryNum];
                        log.info("下一次发送杉德代付查询的时间为:" + time);
                        long delayTimes = time * 1000;
                        accountWithdrawAudit.setQueryNum(queryNum + 1);
                        amqpTemplate.convertAndSend(QueueEnum.QUEUE_DELAYED_SAND_BEHALF.getExchange(), QueueEnum.QUEUE_DELAYED_SAND_BEHALF.getRouteKey(), accountWithdrawAudit, a -> {
                            a.getMessageProperties().setDelay(Math.toIntExact(delayTimes));
                            return a;
                        });
                        log.info("send delay message sandQuery:{}", accountWithdrawAudit.getSn());
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new CustomException(e.getMessage());
        }
    }

    @Override
    public Boolean sandPayStatus(String orderCode) {
        SandSetting sandSetting = sysDictDataService.getObjectData(SandSetting.class);
        // 组后台报文
        JSONObject head = new JSONObject();
        head.put("version", "1.0");
        head.put("method", "sandpay.trade.query");
        head.put("productId", "00000018");
        head.put("accessType", "1");
        head.put("mid", sandSetting.getMid());
        head.put("channelType", "08");
        head.put("reqTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        JSONObject body = new JSONObject();
        body.put("orderCode", orderCode);
        JSONObject data = new JSONObject();
        data.put("head", head);
        data.put("body", body);
        JSONObject resultData = new JSONObject();
        try {
            // 报文签名
            String reqSign = PayServiceImpl.digitalSignShanDe(data.toJSONString());
            //整体报文格式
            Map<String, String> reqMap = new HashMap<>();
            reqMap.put("charset", "UTF-8");
            reqMap.put("data", JSON.toJSONString(data));
            reqMap.put("signType", "01");
            reqMap.put("sign", reqSign);
            reqMap.put("extend", "");

            log.info("请求报文----数据：\n" + JSONObject.toJSONString(JSON.toJSONString(data)));
            log.info("请求报文----签名：\n" + JSONObject.toJSONString(reqSign));
            String result = HttpClient.doPost(sandSetting.getSandUrl() + "/gateway/api/order/query", reqMap, 300000, 600000);
            result = URLDecoder.decode(result, "UTF-8");
            log.info("响应报文：\n" + result);
            Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
            String respData = respMap.get("data");
            JSONObject jsonObject = JSONObject.parseObject(respData);
            String body1 = jsonObject.getString("head");
            if (org.apache.commons.lang3.StringUtils.isNotEmpty(body1)) {
                JSONObject object = JSONObject.parseObject(body1);
                if (!object.getString("respCode").equals("000000")) {
                    throw new CustomException(object.getString("respMsg"));
                } else {
                    return true;
                }
            }
        } catch (Exception e) {
            //log.error(e.getMessage());
            throw new CustomException(e.getMessage());
        }
        return false;
    }

    /**
     * 杉德签名方法
     *
     * @param data 待签名数据
     * @return
     * @throws Exception
     */
    public static String digitalSignShanDe(String data) throws Exception {
        if (null == data) {
            return null;
        } else {
            try {
                SandSetting sandSetting = SpringUtil.getBean(ISysDictDataService.class).getObjectData(SandSetting.class);
                // 获取密钥配置
                // 初始化密钥信息
                CertUtil.init(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword());
                byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
                // 签名
                String signData = new String(org.apache.commons.codec.binary.Base64.encodeBase64(CryptoUtil.digitalSign(sandSetting.getSandPublicPath(), sandSetting.getServerPrivatePath(), sandSetting.getServerPrivatePassword(), dataBytes, CertUtil.getPrivateKey(), "SHA1WithRSA")), StandardCharsets.UTF_8);
                log.info("digitalSign(String) =>>sign:{}", signData);
                return URLEncoder.encode(signData, "UTF-8");
            } catch (Exception var6) {
                log.error("digitalSign(String, String)", var6);
                throw new Exception("签名异常", var6);
            }
        }
    }


    /**
     * 支付宝h5
     *
     * @return
     */
    public static Map<String, String> aliPayConfig2() {
        List<SysDictData> wxPayConfig = DictUtils.getDictCache("alipay_config2");
        Map<String, String> map = new HashMap<>(6);
        assert wxPayConfig != null;
        wxPayConfig.forEach(i -> {
            if ("app_id".equals(i.getDictLabel())) {
                map.put("app_id", i.getDictValue());
            }
            if ("notifyUrl".equals(i.getDictLabel())) {
                map.put("notifyUrl", i.getDictValue());
            }
            if ("notifyUrlCertificate".equals(i.getDictLabel())) {
                map.put("notifyUrlCertificate", i.getDictValue());
            }
            if ("privateKey".equals(i.getDictLabel())) {
                map.put("privateKey", i.getDictValue());
            }
            if ("ALIPAY_PUBLIC_KEY".equals(i.getDictLabel())) {
                map.put("ALIPAY_PUBLIC_KEY", i.getDictValue());
            }
            if ("quit_url".equals(i.getDictLabel())) {
                map.put("quit_url", i.getDictValue());
            }
            if ("return_url".equals(i.getDictLabel())) {
                map.put("return_url", i.getDictValue());
            }
        });
        return map;
    }
}
